package com.iweb.oasys.component;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import java.sql.*;

/**
 * 封装Jdbc 操作数据库CRUD(增删改查)的模板类(工具类)
 */
public class JdbcTemplate {
    /* 构造方法私有化 */
    private JdbcTemplate(){}
    /**
     * 调用此方法, 执行一条插入SQL语句,返回自增长的id
     * @param sql    被执行的SQL语句
     * @param params 该SQL语句中?占位符对应的参数,参数是可变长度的数组类型
     * @return       数据库自增长的id,如果返回 -1说明插入失败
     */
    public static long insertAndResturnId(String sql,Object... params)
    {
        Connection connection = null;
        PreparedStatement pstmt = null;
        long id = -1;
        try {
            /* 向连接池要一个连接对象 */
            connection =  JdbcConnectionPool.getConnection();
            /* 预编译SQL语句,得到预编译对象,在第二个参数位置添加枚举变量,通知数据库插入成功后把自增长的id放入到结果集中*/
            pstmt = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
            /* 判断SQL语句是否会有参数 */
            if(null!=params&&params.length>0)
            {
                /* params不为null,且长度大于1说明外部传了SQL的参数过来,迭代params,替换SQL的?占位符 */
                for (int i = 0; i < params.length; i++) {
                    /* i从0开始的, 但是?占位符的编号从1开始的,所以i+1 */
                    pstmt.setObject(i+1,params[i]);
                }
            }
            /* 执行SQL语句 */
            pstmt.executeUpdate();
            /* 获取存储自增长id的结果集对象 */
            ResultSet resultSet = pstmt.getGeneratedKeys();
            /* 如果结果集有下一行数据 */
            if(resultSet.next())
            {
                /* 取出第一列,赋给id变量 */
                id = resultSet.getInt(1);
            }
        }catch (Exception e)
        {
            e.printStackTrace();
        }finally {
            JdbcConnectionPool.closeConnection(); // 不要忘记在finally块中关闭数据库连接
        }
        return id;  // 返回从结果集中取出的自增长id
    }

    /**
     * 调用此方法, 执行一条DML语句(insert或update或delete), 返回受影响的行数
     * @param sql    被执行的SQL语句
     * @param params 该SQL语句中?占位符对应的参数,参数是可变长度的数组类型
     * @return       受影响的行数
     */
    public static int update(String sql,Object... params)
    {
        Connection connection = null;
        PreparedStatement pstmt = null;
        int row = -1;
        try {
            connection = JdbcConnectionPool.getConnection();
            pstmt = preparedSql(connection, sql, params);
            row = pstmt.executeUpdate();
        }catch (SQLException e)
        {
            e.printStackTrace();
        }
        finally {
            JdbcConnectionPool.closeConnection(); // 不要忘记在finally块中关闭数据库连接
        }
        return row;
    }
    /**
     * 调用此方法, 执行一条DQL语句(select),返回查询的结果集
     * @param sql    被执行的SQL语句
     * @param params 该SQL语句中?占位符对应的参数,参数是可变长度的数组类型
     * @return       查询到的结果集
     */
    public static ResultSet query(String sql,Object... params)
    {
        Connection connection = null;
        PreparedStatement pstmt = null;
        ResultSet resultSet = null;
        try {
            connection = JdbcConnectionPool.getConnection();
            pstmt = preparedSql(connection, sql, params);
            resultSet = pstmt.executeQuery();
        }catch (SQLException e)
        {
            e.printStackTrace();
        }
        return resultSet;
    }
    /**
     * 调用此方法, 执行一条DQL语句(select),返回将查询的结果集转换得到的json格式字符串
     * @param sql    被执行的SQL语句
     * @param params 该SQL语句中?占位符对应的参数,参数是可变长度的数组类型
     * @return       结果集转换得到的json字符串
     */
    public static String queryAndReturnJson(String sql,Object... params)
    {
        return resultSetToJson(query(sql,params));
    }

    /**
     * 因为预编译SQL的操作在本类中所有方法都需要做,因此抽取出公共方法
     * 该方法只提供给本类其他方法使用,故定义为private
     * 因本类其他方法都是静态方法, 故这个公共的方法也需要设置为静态方法
     * 异常抛出给其他调用这个方法的方法处理
     */
    private static PreparedStatement preparedSql(Connection connection,String sql,Object...params)
            throws SQLException
    {
        /* 预编译SQL语句, 得到预编译对象 */
        PreparedStatement pstmt = connection.prepareStatement(sql);
        /* 判断SQL语句是否会有参数 */
        if(null!=params&&params.length>0)
        {
            /* params不为null,且长度大于1说明外部传了SQL的参数过来,迭代params,替换SQL的?占位符 */
            for (int i = 0; i < params.length; i++) {
                /* i从0开始的, 但是?占位符的编号从1开始的,所以i+1 */
                pstmt.setObject(i+1,params[i]);
            }
        }
        return pstmt;
    }

    /**
     * 将结果集ResultSetToJson转为json
     * @param resultSet 需要转为json的结果集
     * @return          json字符串
     */
    public static String resultSetToJson(ResultSet resultSet){
        JSONArray array = new JSONArray();
        try {
            ResultSetMetaData metaData = resultSet.getMetaData();
            int columnCount = metaData.getColumnCount();
            while (resultSet.next()) {
                JSONObject jsonObj = new JSONObject();
                for (int i = 1; i <= columnCount; i++) {
                    String columnName =metaData.getColumnLabel(i);
                    String value = resultSet.getString(columnName);
                    jsonObj.put(columnName, value);
                }
                array.add(jsonObj);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return array.toString();
    }
}
